package com.du.dupload;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TorrentAria implements Runnable {
	/**
	 * Execution flag
	 */
	private boolean executing = false;

	private String filename;

	/**
	 * Splitter cancelation flag
	 */
	private boolean canceled = false;

	private boolean finished = false;

	private boolean error = false;

	private String size = "";

	private String name = "";

	private List<String> out;

	private int progress;

	public TorrentAria(String filename) {
		super();
		this.filename = filename;
		this.out = new ArrayList<String>();
	}

	private synchronized void addOut(String el) {
		out.add(AppConfig.getInstance().getOutDir() + el);
	}

	public synchronized void cancel() {
		this.canceled = true;
	}

	public synchronized void download() throws IllegalStateException {
		while (isExecuting() && isCanceled()) {
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (isExecuting()) {
			return;
		}
		setExecuting(true);
		setCanceled(false);
		setFinished(false);
		setError(false);
		this.out = new ArrayList<String>();
		Thread t = new Thread(this, "Aria torrent started");
		t.start();
	}

	private void downloadProcess() {
		StringBuilder sb = new StringBuilder();
		sb.append("aria2c");
		sb.append(" --seed-time=0 --max-upload-limit=100K --peer-id-prefix=-UT3420-v%8b%1d%a1%211%b4%40%9c%bdJ%cc");
		sb.append(" \"" + filename + "\" ");
		sb.append(" -d " + AppConfig.getInstance().getOutDir());
		System.out.println(AppConfig.getInstance().getOutDir());
		// Execute the command
		System.out.println("Command line: " + sb);
		try {
			final Process p = Runtime.getRuntime().exec(sb.toString());
			Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
				public void run() {
					p.destroyForcibly();
				}
			}));

			// Read the response
			BufferedReader input = new BufferedReader(new InputStreamReader(
					p.getInputStream()));
			BufferedReader error = new BufferedReader(new InputStreamReader(
					p.getErrorStream()));
			

			String line = input.readLine();
			while (line != null && !isCanceled()) {
				System.out.println("\t***" + line);
				Pattern pat = Pattern.compile("\\[.*?\\((\\d*?)%\\).*?\\]");
				Matcher m = pat.matcher(line);
				if (m.matches()) {
					setProgress(Integer.parseInt(m.group(1)));
				}
				line = input.readLine();
			}

			line = error.readLine();
			while (line != null && !isCanceled()) {
				System.out.println("\t***" + line);
				line = error.readLine();
			}
			p.destroyForcibly();
		} catch (Exception e) {
			setError(true);
		}

		System.out.println("end part: of downl");
	}

	private void getInfo() {
		// System.out.println("Execute Inquiry for file: " + filename);

		try {
			// Build the command line
			StringBuilder sb = new StringBuilder();
			sb.append("aria2c");
			sb.append(" -S ");
			sb.append(" \"" + filename + "\" ");
			sb.append(" -d " + AppConfig.getInstance().getOutDir() + " --peer-id-prefix=-UT3420-v%8b%1d%a1%211%b4%40%9c%bdJ%cc");

			// Execute the command
			System.out.println("Command line: " + sb);
			Process p = Runtime.getRuntime().exec(sb.toString());
			Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
				public void run() {
					p.destroyForcibly();
				}
			}));

			// Read the response
			BufferedReader input = new BufferedReader(new InputStreamReader(
					p.getInputStream()));
			BufferedReader error = new BufferedReader(new InputStreamReader(
					p.getErrorStream()));

			// Parse the input stream
			String line = input.readLine();
			while (line != null) {
				// System.out.println("\t***" + line);
				Pattern pat = Pattern.compile("  \\d*?\\|\\.(.+?)$");
				Matcher m = pat.matcher(line);
				if (m.matches()) {
					addOut(m.group(1).substring(1));
				}
				pat = Pattern.compile("Length: (.*?)\\(");
				m = pat.matcher(line);
				if (m.matches()) {
					setSize(m.group(1));
				}

				pat = Pattern.compile("Name: (.*?)$");
				m = pat.matcher(line);
				if (m.matches()) {
					setName(m.group(1));
				}
				line = input.readLine();
			}

			line = error.readLine();
			while (line != null) {
				line = error.readLine();
			}
			p.destroyForcibly();
		} catch (Exception e) {
			setError(true);
		}
		if (out.isEmpty()) {
			setError(true);
		}

		// Debug: dump fields:

	}

	public synchronized String getName() {
		return name;
	}

	private synchronized void setName(String name) {
		this.name = name;
	}

	public synchronized int getProgress() {
		return progress;
	}

	public synchronized List<String> getResult() {
		if (isFinished()) {
			return new ArrayList<String>(out);
		} else {
			return new ArrayList<String>();
		}
	}

	public synchronized String getSize() {
		return size;
	}

	public synchronized boolean isCanceled() {
		return canceled;
	}

	public synchronized boolean isError() {
		return error;
	}

	public synchronized boolean isExecuting() {
		return executing;
	}

	public synchronized boolean isFinished() {
		return finished;
	}

	@Override
	public void run() {
		getInfo();
		downloadProcess();
		if (!isCanceled()) {
			setFinished(true);
		}
		setExecuting(false);
	}

	private synchronized void setCanceled(boolean canceled) {
		this.canceled = canceled;
	}

	private synchronized void setError(boolean error) {
		this.error = error;
		if (error == true)
			this.canceled = true;
	}

	private synchronized void setExecuting(boolean executing) {
		this.executing = executing;
	}

	private synchronized void setFinished(boolean finished) {
		this.finished = finished;
	}

	private synchronized void setProgress(int progress) {
		this.progress = progress;
	}

	private synchronized void setSize(String size) {
		this.size = size;
	}

}
